//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

import React, { useCallback, useEffect, useRef, useState } from 'react';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { DndProvider } from 'react-dnd';
import ReactFlow, { Background, Controls, Panel, ReactFlowProvider } from 'reactflow';
import type { Node as FlowNode, XYPosition, OnNodesChange, NodePositionChange, NodeDimensionChange } from 'reactflow';
import { type DropTargetMonitor, useDrop } from "react-dnd";
import 'reactflow/dist/base.css';
import { DND_ITEM_TYPE, NODE_TYPE_BASE_GROUP } from './compoents/local_nodes/types';
import type { NodeData } from './compoents/local_nodes/types';
import LocalNodeTreePanel from './compoents/local_nodes/LocalNodeTreePanel';
import { uniqId } from '@/utils/utils';
import { observer } from 'mobx-react';
import { allNodeTyps, getNodeTypeStr } from './compoents/local_nodes/helper';
import { useSize } from 'ahooks';
import { useDataViewStores } from './store';

const LocalDataViewEditor = observer(() => {
    const dataViewStore = useDataViewStores();

    const divRef = useRef<HTMLDivElement>(null);
    const divSize = useSize(divRef);
    const [nodes, setNodes] = useState<FlowNode[]>([]);

    const addNode = (itemData: NodeData, position: XYPosition) => {
        const tmpNodeList = dataViewStore.localStore.nodeList.slice();

        tmpNodeList.push({
            id: uniqId(),
            position: position,
            data: itemData,
            width: itemData.width,
            height: itemData.height,
            type: getNodeTypeStr(itemData.nodeType),
            zIndex: itemData.nodeType == NODE_TYPE_BASE_GROUP ? 10 : 1000,
        });
        dataViewStore.localStore.nodeList = tmpNodeList;
        dataViewStore.localStore.saveNodeList();
    };

    const [_, drop] = useDrop(() => ({
        accept: DND_ITEM_TYPE,
        drop: (itemData: NodeData, monitor: DropTargetMonitor<NodeData, void>) => {
            if (dataViewStore.localStore.flowInstance != null) {
                const clientOffset = monitor.getClientOffset();
                const position = dataViewStore.localStore.flowInstance.screenToFlowPosition({
                    x: (clientOffset?.x ?? 0),
                    y: (clientOffset?.y ?? 0),
                });
                addNode(Object.assign({}, itemData), position);
            }
        },
        canDrop: () => true,
    }));

    const onNodesChange: OnNodesChange = useCallback(
        (changes) => {
            for (const change of changes) {
                if (change.type == "position") {
                    const realChange = change as NodePositionChange;
                    if (realChange.dragging) {
                        dataViewStore.localStore.updateNodePosition(change.id, Math.round(realChange.position?.x ?? 0), Math.round(realChange.position?.y ?? 0));
                    } else {
                        dataViewStore.localStore.updateNodePositionEnd(change.id);
                        dataViewStore.localStore.saveNodeList();
                    }
                } else if (change.type == "dimensions") {
                    const realChange = change as NodeDimensionChange;
                    if (realChange.resizing) {
                        dataViewStore.localStore.updateNodeSize(change.id, Math.round(realChange.dimensions?.width ?? 0), Math.round(realChange.dimensions?.height ?? 0));
                    } else if (realChange.resizing == false) {
                        dataViewStore.localStore.saveNodeList();
                    }
                }
            }
        },
        [setNodes]
    );


    useEffect(() => {
        setNodes(dataViewStore.localStore.nodeList);
        // console.log(dataViewStore.nodeList);
    }, [dataViewStore.localStore.nodeList]);

    useEffect(() => {
        dataViewStore.localStore.flowInstance?.fitView();
    }, [divSize?.height, divSize?.width]);

    return (
        <ReactFlowProvider>
            <div ref={divRef} style={{ width: "100vw", height: "100vh" }}>
                <ReactFlow ref={drop} nodes={nodes} onInit={(instance) => dataViewStore.localStore.flowInstance = instance}
                    deleteKeyCode={null}
                    onNodesChange={onNodesChange}
                    nodeTypes={allNodeTyps}
                    fitView>
                    <Background color="#eee" style={{ backgroundColor: "#eee" }} />
                    <Controls position='top-right' />
                    <Panel position="top-left">
                        <LocalNodeTreePanel />
                    </Panel>
                </ReactFlow>
            </div>
        </ReactFlowProvider>
    );
});

const LocalDataViewBoard = () => {
    return (
        <DndProvider backend={HTML5Backend}>
            <LocalDataViewEditor />
        </DndProvider>
    );
};

export default LocalDataViewBoard;